package com.winit.schedule.task.tracker.runner;

import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.winit.schedule.core.model.AssignedTask;
import com.winit.schedule.core.model.Task;
import com.winit.schedule.core.model.TaskItem;
import com.winit.schedule.core.repository.constants.TaskStatus;
import com.winit.schedule.core.repository.entity.TaskItemEntity;
import com.winit.schedule.core.task.ScheduleTaskDealSingle;
import com.winit.schedule.core.utils.Clock;
import com.winit.schedule.task.tracker.utils.ExceptionUtils;

/**
 * 单线程任务执行器
 * 
 * @author jianke.zhang 2015-4-22 上午9:54:58
 * @since 1.0
 */
public class SingleThreadTaskRunner implements TaskRunner, Runnable {

    private static transient Logger  logger             = LoggerFactory.getLogger(SingleThreadTaskRunner.class);

    Thread                           taskThread;

    /**
     * 任务管理器
     */
    protected AbstractTaskManager    taskManager;

    protected AssignedTask           assignedTask;

    /**
     * 传递给任务执行接口的参数
     */
    private Task                     task;

    /**
     * 任务分析
     */
    protected StatisticsInfo         statisticsInfo;

    /**
     * 队列处理器
     */
    protected ScheduleTaskDealSingle taskDealBean;

    boolean                          isSleeping         = false;

    boolean                          isStop             = false;

    boolean                          isCompleteSchedule = false;

    /**
     * 线程调度锁对象
     */
    final ThreadScheduleLockObject   ts_lockObject      = new ThreadScheduleLockObject();

    public SingleThreadTaskRunner(AbstractTaskManager taskManager, ScheduleTaskDealSingle taskDealBean,
                                  StatisticsInfo statisticsInfo){
        this.taskManager = taskManager;
        this.taskDealBean = taskDealBean;
        this.statisticsInfo = statisticsInfo;
        this.assignedTask = taskManager.getTask();

        this.task = buildTask(assignedTask);

        taskThread = new Thread(this);
        String threadName = this.taskManager.getTask().getTaskId() + "-" + this.taskManager.getCurrentSerialNumber()
                            + "-exe-" + 0;
        taskThread.setName(threadName);
        taskThread.start();
    }

    private Task buildTask(AssignedTask assignedTask) {
        Task task = new Task();
        task.setEachFetchDataNum(assignedTask.getEachFetchDataNum());
        task.setTaskParameter(assignedTask.getTaskParameter());

        List<TaskItem> taskItems = new ArrayList<TaskItem>();
        if (assignedTask.getTaskItems() != null) {
            for (TaskItemEntity item : assignedTask.getTaskItems()) {
                taskItems.add(new TaskItem(item.getTaskItemId(), item.getParameter()));
            }
            task.setTaskItems(taskItems);
        }
        return task;
    }

    @Override
    public boolean isDealFinishAllData() {
        return false;
    }

    @Override
    public boolean isSleeping() {
        return this.isSleeping;
    }

    public void completeSchedule() throws Exception {
        this.isCompleteSchedule = true;
        this.stopTask(false);
    }

    @Override
    public void stopTask(boolean force) throws Exception {
        this.isStop = true;
        
        if (force && null != taskThread) {
            try {
                if (!taskThread.isInterrupted()) {
                    taskThread.interrupt();
                }
            } catch (Throwable e) {

            }
        }
    }

    @Override
    public void clearAllHasFetchData() {

    }

    @Override
    public void run() {

        long startTime = Clock.getSystemTime();
        try {
            while (true) {

                if (this.isStop == true) {// 停止队列调度
                    break;
                }

                try {
                    // 运行相关的程序
                    if (this.taskDealBean.execute(this.task) == true) {
                        addSuccessNum(1,
                            Clock.getSystemTime() - startTime,
                            "com.winit.schedule.task.tracker.runner.SingleThreadTaskRunner.run");
                    } else {
                        addFailNum(1,
                            Clock.getSystemTime() - startTime,
                            "com.winit.schedule.task.tracker.runner.SingleThreadTaskRunner.run");
                        this.taskManager.fireTaskExecuteFailure(null);
                    }
                } catch (Throwable ex) {
                    addFailNum(1,
                        Clock.getSystemTime() - startTime,
                        "com.winit.schedule.task.tracker.runner.SingleThreadTaskRunner.run");
                    logger.warn("Task :" + assignedTask + " failure", ex);
                    this.taskManager.fireTaskExecuteFailure(ExceptionUtils.getStackTrace(ex));
                }

                if (assignedTask.getPermitRunEndTime() <= 0) {
                    // 未设定结束时间执行完任务后立即结束
                    this.isCompleteSchedule = true;
                    break;
                } else {
                    // 在处理完毕后休眠固定的时间
                    if (this.assignedTask.getSleepTimeInterval() > 0) {

                        if (logger.isTraceEnabled()) {
                            logger.trace("Finished processing execute after dormancy："
                                         + this.assignedTask.getSleepTimeInterval());
                        }
                        this.isSleeping = true;
                        Thread.sleep(assignedTask.getSleepTimeInterval());
                        this.isSleeping = false;

                        if (logger.isTraceEnabled()) {
                            logger.trace("Finished processing execute recovery after dormancy");
                        }
                    }
                }

            }

            if (this.isStop && !this.isCompleteSchedule) {
                // 任务结束
                this.taskManager.completeTask(TaskStatus.STOP, null);
            } else {
                // 任务结束
                this.taskManager.completeTask(TaskStatus.COMPLETE, null);
            }
        } catch (InterruptedException ex) {
            addFailNum(1, Clock.getSystemTime() - startTime, "SingleThreadTaskRunner.run");
            logger.warn("Task :" + assignedTask + " failure", ex);
            this.taskManager.completeTask(TaskStatus.STOP, null);
        } catch (Throwable ex) {
            addFailNum(1, Clock.getSystemTime() - startTime, "SingleThreadTaskRunner.run");
            logger.warn("Task :" + assignedTask + " failure", ex);
            this.taskManager.completeTask(TaskStatus.RUNNER_FAILURE, ExceptionUtils.getStackTrace(ex));
        }
    }

    public int getThreadNum() {
        return 1;
    }

    public void addFetchNum(long num, String addr) {

        this.statisticsInfo.addFetchDataCount(1);
        this.statisticsInfo.addFetchDataNum(num);
    }

    public void addSuccessNum(long num, long spendTime, String addr) {
        this.statisticsInfo.addDealDataSucess(num);
        this.statisticsInfo.addDealSpendTime(spendTime);
    }

    public void addFailNum(long num, long spendTime, String addr) {
        this.statisticsInfo.addDealDataFail(num);
        this.statisticsInfo.addDealSpendTime(spendTime);
    }

}
